using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;

namespace DocLibApp
{
    #region Class ListViewColumnSorter
    public class ListViewColumnSorter :  System.Collections.IComparer
    {
        /// <summary>
        /// Specifies the column to be sorted
        /// </summary>
        private int ColumnToSort;
        /// <summary>
        /// Specifies the order in which to sort (i.e. 'Ascending').
        /// </summary>
        private SortOrder OrderOfSort;
        /// <summary>
        /// Case insensitive comparer object
        /// </summary>
        private System.Collections.CaseInsensitiveComparer ObjectCompare;

        /// <summary>
        /// Class constructor.  Initializes various elements
        /// </summary>
        public ListViewColumnSorter()
        {
            // Initialize the column to '0'
            ColumnToSort = 0;

            // Initialize the sort order to 'none'
            OrderOfSort = SortOrder.None;

            // Initialize the CaseInsensitiveComparer object
            ObjectCompare = new System.Collections.CaseInsensitiveComparer();
        }

        /// <summary>
        /// This method is inherited from the IComparer interface.  It compares the two objects passed using a case insensitive comparison.
        /// </summary>
        /// <param name="x">First object to be compared</param>
        /// <param name="y">Second object to be compared</param>
        /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
        public int Compare(object x, object y)
        {
            int compareResult;
            ListViewItem listviewX, listviewY;

            // Cast the objects to be compared to ListViewItem objects
            listviewX = (ListViewItem)x;
            listviewY = (ListViewItem)y;

            // Compare the two items
            compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);

            // Calculate correct return value based on object comparison
            if (OrderOfSort == SortOrder.Ascending)
            {
                // Ascending sort is selected, return normal result of compare operation
                return compareResult;
            }
            else if (OrderOfSort == SortOrder.Descending)
            {
                // Descending sort is selected, return negative result of compare operation
                return (-compareResult);
            }
            else
            {
                // Return '0' to indicate they are equal
                return 0;
            }
        }

        /// <summary>
        /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
        /// </summary>
        public int SortColumn
        {
            set
            {
                ColumnToSort = value;
            }
            get
            {
                return ColumnToSort;
            }
        }

        /// <summary>
        /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
        /// </summary>
        public SortOrder Order
        {
            set
            {
                OrderOfSort = value;
            }
            get
            {
                return OrderOfSort;
            }
        }

    }
    #endregion // EO Class ListViewSorter

    /// <summary>
	/// Summary description for mylistview.
	/// </summary>
	public class mylistview : System.Windows.Forms.ListView
	{
		#region my variables
        private bool bUseColumnDescription = false;

        private int tagFieldIndex = -1; //index of columns used as tag

        private bool bUseAltRowColor = true;
		private ListViewColumnSorter lvsorter;

        //drag n drop items
        private const string REORDER = "Reorder";
        private bool allowRowReorder = true;

        public bool UseAltColor
        {
            get
            {
                return bUseAltRowColor;
            }

            set
            {
                bUseAltRowColor = value;
            }
        }

        public bool AllowRowReorder
        {
            get
            {
                return this.allowRowReorder;
            }
            set
            {
                this.allowRowReorder = value;
                //base.AllowDrop = value;
            }
        }

        public bool UseColumnDescription
        {
            get
            {
                return bUseColumnDescription;
            }
            set
            {
                bUseColumnDescription = value;
            }
        }

        public new SortOrder Sorting
        {
            get
            {
                return SortOrder.None;
            }
            set
            {
                base.Sorting = SortOrder.None;
            }
        }
		#endregion

		public mylistview() : base()
		{
			InitializeComponent();

            //initialize listviewsorter
			lvsorter = new ListViewColumnSorter();
			this.ListViewItemSorter = lvsorter;

            this.AllowRowReorder = true;
		}

		private void listView1_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)
		{
			// Determine if clicked column is already the column that is being sorted.
			if ( e.Column == lvsorter.SortColumn )
			{
				// Reverse the current sort direction for this column.
				if (lvsorter.Order == SortOrder.Ascending)
				{
					lvsorter.Order = SortOrder.Descending;
				}
				else
				{
					lvsorter.Order = SortOrder.Ascending;
				}
			}
			else
			{
				// Set the column number that is to be sorted; default to ascending.
				lvsorter.SortColumn = e.Column;
				lvsorter.Order = SortOrder.Ascending;
			}

			// Perform the sort with these new sort options.
			this.Sort();
		}

		private void InitializeComponent()
		{
            this.SuspendLayout();
            // 
            // mylistview
            // 
            this.FullRowSelect = true;
            this.GridLines = true;
            this.Sorting = System.Windows.Forms.SortOrder.Ascending;
            this.View = System.Windows.Forms.View.Details;
            this.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listView1_ColumnClick);
            this.KeyUp +=new KeyEventHandler(mylistview_KeyUp);
            this.ResumeLayout(false);

        }

        private void mylistview_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyData)
            {
                case Keys.Delete:
                    DeleteSelectedItems();
                    break;
                default:
                    break;
            }
        }

        private void DeleteSelectedItems()
        {
            if (this.SelectedItems.Count > 0)
            {
                foreach (ListViewItem aitem in this.SelectedItems)
                {
                    this.Items.Remove(aitem);
                }
            }
        }

        #region Utility Functions
        public void setupColumn(System.Collections.ArrayList Columns)
        {
            this.Clear();
            this.View = System.Windows.Forms.View.Details;
            this.MultiSelect = false;
            this.HideSelection = false;
            this.FullRowSelect = true;

            //setup columns for list view
            foreach (object colObj in Columns)
            {
                string column = ("" + colObj).Trim();
                string[] columnspec = column.Split(new char[] { '@' });
                string columnName = columnspec[0].ToString().Trim();
                int columnWidth = Int32.Parse(columnspec[1].ToString().Trim());

                System.Windows.Forms.ColumnHeader header = new System.Windows.Forms.ColumnHeader();
                header.Text = columnName;
                header.Width = columnWidth;

                this.Columns.Add(header);
            }
        }

        /// <summary>
        /// Read a list value in a string into a list view
        /// </summary>
        /// <param name="Columns">array of string in format of columnName@width, to setup listview </param>
        /// <param name="IsDataIncludeHeader">Does the input string data includes the first line as the header</param>
        /// <param name="sData">Data string in format of:
        /// subitem1,subitem2,subitem3
        /// subitemA, subitemB, subitemC
        /// </param>
        public void ReadValueIntoListView(System.Collections.ArrayList Columns, string sData, bool IsDataIncludeHeader)
        {
            char sepLine = '\n';  //separator for lines
            char sepItem = ',';  //separator for items

            this.Clear();
            this.View = System.Windows.Forms.View.Details;
            this.MultiSelect = false;
            this.HideSelection = false;
            this.FullRowSelect = true;

            //setup columns for list view
            foreach (object colObj in Columns)
            {
                string column = ("" + colObj).Trim();
                string[] columnspec = column.Split(new char[] { '@' });
                string columnName = columnspec[0].ToString().Trim();
                int columnWidth = Int32.Parse(columnspec[1].ToString().Trim());

                System.Windows.Forms.ColumnHeader header = new System.Windows.Forms.ColumnHeader();
                header.Text = columnName;
                header.Width = columnWidth;

                this.Columns.Add(header);
            }

            //populate data
            string[] lines = sData.Split(sepLine);

            int count = 0;

            foreach (string aLine in lines)
            {
                if (aLine != "")
                {
                    count++;
                    string[] items = aLine.Split(sepItem);
                    System.Windows.Forms.ListViewItem newItem = null;

                    foreach (string subItem in items)
                    {
                        string aitem = subItem.Trim();

                        if (aitem != "")
                        {
                            if (newItem == null)
                                newItem = new ListViewItem(aitem);
                            else
                                newItem.SubItems.Add(aitem);
                        }
                    }

                    if (newItem != null)
                    {
                        if (!IsDataIncludeHeader)
                            this.Items.Add(newItem);
                        else if (IsDataIncludeHeader && count > 1)
                            this.Items.Add(newItem);
                    }
                }

            }
        }

        /// <summary>
		/// Reads csv string and populate a listview.
		/// </summary>
		/// <param name="Columns">ArrayList contains (ColumnName@Column Width)</param>
		/// <param name="sData">csv string contains data</param>
		/// <param name="IsDataIncludeHeader">Does sData contain header columns</param>
		/// <param name="LineSeparator">Line Seperator string</param>
		public void ReadValueIntoListView(System.Collections.ArrayList Columns, string sData, bool IsDataIncludeHeader, string LineSeparator)
		{
			char sepLine = '\n';  //separator for lines
			char sepItem = ',';  //separator for items

			if (LineSeparator != "")
				sepLine = char.Parse(LineSeparator);

			this.Clear();
			this.View = View.Details;
			this.MultiSelect = false;
			this.HideSelection = false;
			this.FullRowSelect = true;

			//setup columns for list view
			foreach (object colObj in Columns)
			{
				string column = ("" + colObj).Trim();
				string[] columnspec = column.Split(new char[] { '@' });
				string columnName = columnspec[0].ToString().Trim();
				int columnWidth = Int32.Parse(columnspec[1].ToString().Trim());

				ColumnHeader header = new ColumnHeader();
				header.Text = columnName;
				header.Width = columnWidth;

				this.Columns.Add(header);
			}

			//populate data
			string[] lines = sData.Split(sepLine);

			int count = 0;

			foreach (string aLine in lines)
			{
				if (aLine != "")
				{
					count++;
					string[] items = aLine.Split(sepItem);
					ListViewItem newItem = null;

					foreach (string subItem in items)
					{
						string aitem = subItem.Trim();

						if (aitem != "")
						{
							if (newItem == null)
								newItem = new ListViewItem(subItem);
							else
								newItem.SubItems.Add(subItem);
						}
					}

					if (newItem != null)
					{
						if (!IsDataIncludeHeader)
							this.Items.Add(newItem);
						else if (IsDataIncludeHeader && count > 1)
							this.Items.Add(newItem);
					}
				}

			}
		}


		/// <summary>
		/// Save ListView data into a csv file
		/// </summary>
		/// <param name="bIncludeHeader">save the column headers as the first row in csv file</param>
		/// <returns>string with data </returns>
		public string SaveListViewDataToCSV(bool bIncludeHeader)
		{
			string sOutput = "";

			string sepLine = "\n"; //separator for line
			string sepItem = ",";//separator for item

			if (this.Items.Count >0)
			{
				if (this.Columns.Count > 0)
				{
					//create heading
					string sHeaderline = ""; //header line for column heading information
					foreach (ColumnHeader col in this.Columns)
					{
						if (sHeaderline.Trim() != "")
							sHeaderline += sepItem + col.Text.Trim();
						else
							sHeaderline = col.Text.Trim();
					}

					sHeaderline += "\n";

					//create data
					string sItemData = "";
					foreach (ListViewItem item in this.Items)
					{
						string sItemLine = "";

						foreach (ListViewItem.ListViewSubItem subItem in item.SubItems)
						{
							if (sItemLine != "")
								sItemLine += sepItem + subItem.Text.Trim();
							else
								sItemLine = subItem.Text.Trim();
						}

						if (sItemData != "")
							sItemData += sepLine + sItemLine;
						else
							sItemData = sItemLine;
					}

					if (bIncludeHeader)
						sOutput = sHeaderline + sItemData;
					else
						sOutput = sItemData;
				}
				else //ONLY 1 column
				{
					string sItemData = "";

					foreach (ListViewItem item in this.Items)
					{
						if (sItemData.Trim() != "")
							sItemData += sepLine + item.Text.Trim();
						else
							sItemData = item.Text.Trim();
					}

					if (bIncludeHeader)
						sOutput = this.Columns[0].Text.Trim() + sepLine + sItemData;
					else
						sOutput = sItemData;
				}
			}

			return sOutput;
		}

		/// <summary>
		/// Save the items from ListView into a CSV string
		/// </summary>
		/// <param name="lsv">ListView</param>
		/// <param name="bIncludeHeader">Include column header information in csv?</param>
		/// <param name="LineSeparator">Line Seperator string</param>
		/// <returns></returns>
		public string SaveListViewDataToCSV(bool bIncludeHeader, string LineSeparator)
		{
			string sOutput = "";

			string sepLine = "\n"; //separator for line
			string sepItem = ",";//separator for item

			if (LineSeparator != "")
				sepLine = LineSeparator;

			if (this.Items.Count >0)
			{
				if (this.Columns.Count > 0)
				{
					//create heading
					string sHeaderline = ""; //header line for column heading information
					foreach (ColumnHeader col in this.Columns)
					{
						if (sHeaderline.Trim() != "")
							sHeaderline += sepItem + col.Text.Trim();
						else
							sHeaderline = col.Text.Trim();
					}

					sHeaderline += "\n";

					//create data
					string sItemData = "";
					foreach (ListViewItem item in this.Items)
					{
						string sItemLine = "";

						foreach (ListViewItem.ListViewSubItem subItem in item.SubItems)
						{
							if (sItemLine != "")
								sItemLine += sepItem + subItem.Text.Trim();
							else
								sItemLine = subItem.Text.Trim();
						}

						if (sItemData != "")
							sItemData += sepLine + sItemLine;
						else
							sItemData = sItemLine;
					}

					if (bIncludeHeader)
						sOutput = sHeaderline + sItemData;
					else
						sOutput = sItemData;
				}
				else //ONLY 1 column
				{
					string sItemData = "";

					foreach (ListViewItem item in this.Items)
					{
						if (sItemData.Trim() != "")
							sItemData += sepLine + item.Text.Trim();
						else
							sItemData = item.Text.Trim();
					}

					if (bIncludeHeader)
						sOutput = this.Columns[0].Text.Trim() + sepLine + sItemData;
					else
						sOutput = sItemData;
				}
			}

			return sOutput;
        }

        /// <summary>
        /// load List of string into a one column listview, with the string as the tag
        /// </summary>
        /// <param name="DataList"></param>
        public void ShowData(List<string> DataList)
        {
            bool bDiffBackColor = false;

            if (this.Items.Count > 0)
                this.Items.Clear();

            foreach (string aData in DataList)
            {
                if (bDiffBackColor)
                    bDiffBackColor = false;
                else
                    bDiffBackColor = true;

                ListViewItem aitem = new ListViewItem(aData);
                aitem.Tag = aData;

                if (bUseAltRowColor && bDiffBackColor)
                {
                    aitem.BackColor = Color.BurlyWood;
                }

                this.Items.Add(aitem);
            }
        }

        /// <summary>
        /// Show ArrayList of Data in ListView, given TableName would use the Column Description defined in the system
        /// </summary>
        /// <param name="DataList"></param>
        /// <param name="tagField"></param>
        /// <param name="TableName"></param>
        public void ShowData(System.Collections.ArrayList DataList, string tagField, string TableName)
        {
            bool bDiffBackColor = false;

            if (DataList.Count > 0)
            {
                if (this.Items.Count > 0)
                    this.Items.Clear();

                for (int i = 0; i < DataList.Count; i++)
                {
                    if (DataList[i] is List<string>)
                    {
                        List<string> line = (List<string>)DataList[i];

                        if (i == 0)
                        {
                            if (this.Columns.Count == 0)
                            {
                                for (int k = 0; k < line.Count; k++)
                                {
                                    string aField = line[k];

                                    if (aField == tagField)
                                        tagFieldIndex = k;
                                    
                                    aField = doc_system.GetColumnDescription(TableName, aField);

                                    this.Columns.Add(aField);
                                }
                            }
                        }
                        else
                        {
                            if (bDiffBackColor)
                                bDiffBackColor = false;
                            else
                                bDiffBackColor = true;

                            ListViewItem aitem = new ListViewItem();
                            for (int j = 0; j < line.Count; j++)
                            {
                                if (j == tagFieldIndex)
                                    aitem.Tag = line[j];

                                if (j == 0)
                                    aitem.Text = line[j];
                                else
                                    aitem.SubItems.Add(line[j]);
                            }

                            if (bUseAltRowColor && bDiffBackColor)
                            {
                                aitem.BackColor = Color.BurlyWood;
                            }

                            this.Items.Add(aitem);
                        }
                    }
                }

                this.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
            }
            else
            {
                this.Items.Clear();
            }
        }

        /// <summary>
        /// Display data given a list of tag fields (the listview item's tag is a hashtable of ht[tag fieldname] = field value
        /// </summary>
        /// <param name="DataList"></param>
        /// <param name="TagFields"></param>
        public void ShowData(System.Collections.ArrayList DataList, List<string> TagFields)
        {
            bool bDiffBackColor = false;

            if (DataList.Count > 0)
            {
                List<string> tagFieldIndex = new List<string>();

                if (this.Items.Count > 0)
                    this.Items.Clear();

                for (int i = 0; i < DataList.Count; i++)
                {
                    if (DataList[i] is List<string>)
                    {
                        List<string> line = (List<string>)DataList[i];

                        if (i == 0)
                        {
                            if (this.Columns.Count == 0)
                            {
                                for (int k = 0; k < line.Count; k++)
                                {
                                    string aField = line[k];

                                    if (TagFields.Contains(aField))
                                        tagFieldIndex.Add(k.ToString());

                                    this.Columns.Add(aField);
                                }
                            }
                        }
                        else
                        {
                            if (bDiffBackColor)
                                bDiffBackColor = false;
                            else
                                bDiffBackColor = true;

                            ListViewItem aitem = new ListViewItem();
                            System.Collections.Hashtable htTagFieldValues = new System.Collections.Hashtable();
                            for (int j = 0; j < line.Count; j++)
                            {
                                if (tagFieldIndex.Contains(j.ToString()))
                                {
                                    List<string> FieldList = (List<string>)DataList[0];
                                    string tagFieldName = FieldList[j].ToString();
                                    string tagFieldValue = line[j].ToString();

                                    htTagFieldValues[tagFieldName] = tagFieldValue;
                                }

                                if (j == 0)
                                    aitem.Text = line[j];
                                else
                                    aitem.SubItems.Add(line[j]);
                            }
                            aitem.Tag = htTagFieldValues;

                            if (bUseAltRowColor && bDiffBackColor)
                            {
                                aitem.BackColor = Color.Coral;
                            }

                            this.Items.Add(aitem);
                        }
                    }
                }

                this.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
            }
            else
            {
                this.Items.Clear();
            }
        }

        /// <summary>
        /// Show Data from ArrayList of Data
        /// </summary>
        /// <param name="DataList">Array List of List of string </String></param>
        public void ShowData(System.Collections.ArrayList DataList, string tagField)
        {
            bool bDiffBackColor = false;

            if (DataList.Count > 0)
            {
                if (this.Items.Count > 0)
                    this.Items.Clear();

                for (int i = 0; i < DataList.Count; i++)
                {
                    if (DataList[i] is List<string>)
                    {
                        List<string> line = (List<string>)DataList[i];

                        if (i == 0)
                        {
                            if (this.Columns.Count == 0)
                            {
                                for (int k = 0; k < line.Count; k++)
                                {
                                    string aField = line[k];

                                    if (aField == tagField)
                                        tagFieldIndex = k;

                                    this.Columns.Add(aField);
                                }
                            }
                        }
                        else
                        {
                            if (bDiffBackColor)
                                bDiffBackColor = false;
                            else
                                bDiffBackColor = true;

                            ListViewItem aitem = new ListViewItem();
                            for (int j = 0; j < line.Count; j++)
                            {
                                if (j == tagFieldIndex)
                                    aitem.Tag = line[j];

                                if (j == 0)
                                    aitem.Text = line[j];
                                else
                                    aitem.SubItems.Add(line[j]);
                            }

                            if (bUseAltRowColor && bDiffBackColor)
                            {
                                aitem.BackColor = Color.BurlyWood;
                            }

                            this.Items.Add(aitem);
                        }
                    }
                }

                this.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
            }
            else
            {
                this.Items.Clear();
            }
        }

        /// <summary>
        /// Save ListView Items' tag into a string list
        /// </summary>
        /// <returns></returns>
        public List<string> SaveItemsIntoStringList()
        {
            List<string> alist = new List<string>();

            foreach (ListViewItem aitem in this.Items)
            {
                if (aitem.Tag != null && !string.IsNullOrEmpty(aitem.Tag.ToString()))
                {
                    string tag = aitem.Tag.ToString().Trim();
                    if (!alist.Contains(tag))
                        alist.Add(tag);
                }
            }

            return alist;
        }

        /// <summary>
        /// Check to see if a item already in the list (given the tag value)
        /// </summary>
        /// <param name="tagvalue"></param>
        /// <returns></returns>
        public bool IsItemAlreadyInList(string tagvalue)
        {
            foreach (ListViewItem aitem in this.Items)
            {
                if (aitem.Tag != null && aitem.Tag.ToString().Trim() == tagvalue)
                    return true;
            }

            return false;
        }
        #endregion //EO utility functions

        #region Reorder Item drag n drop
        protected override void OnDragDrop(DragEventArgs e)
        {
            base.OnDragDrop(e);
            if (!this.AllowRowReorder)
            {
                return;
            }
            if (base.SelectedItems.Count == 0)
            {
                return;
            }
            Point cp = base.PointToClient(new Point(e.X, e.Y));
            ListViewItem dragToItem = base.GetItemAt(cp.X, cp.Y);
            if (dragToItem == null)
            {
                return;
            }
            int dropIndex = dragToItem.Index;
            if (dropIndex > base.SelectedItems[0].Index)
            {
                dropIndex++;
            }

            System.Collections.ArrayList insertItems = new System.Collections.ArrayList(base.SelectedItems.Count);

            foreach (ListViewItem item in base.SelectedItems)
            {
                insertItems.Add(item.Clone());
            }
            for (int i = insertItems.Count - 1; i >= 0; i--)
            {
                ListViewItem insertItem =
                    (ListViewItem)insertItems[i];
                base.Items.Insert(dropIndex, insertItem);
            }
            foreach (ListViewItem removeItem in base.SelectedItems)
            {
                base.Items.Remove(removeItem);
            }
        }

        protected override void OnDragOver(DragEventArgs e)
        {
            if (!this.AllowRowReorder)
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            Point cp = base.PointToClient(new Point(e.X, e.Y));
            ListViewItem hoverItem = base.GetItemAt(cp.X, cp.Y);
            if (hoverItem == null)
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            foreach (ListViewItem moveItem in base.SelectedItems)
            {
                if (moveItem.Index == hoverItem.Index)
                {
                    e.Effect = DragDropEffects.None;
                    hoverItem.EnsureVisible();
                    return;
                }
            }
            base.OnDragOver(e);

            String text = (String)e.Data.GetData(REORDER.GetType());
            if (text.CompareTo(REORDER) == 0)
            {
                e.Effect = DragDropEffects.Move;
                hoverItem.EnsureVisible();
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        protected override void OnDragEnter(DragEventArgs e)
        {
            base.OnDragEnter(e);
            if (!this.AllowRowReorder)
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            base.OnDragEnter(e);
            String text = (String)e.Data.GetData(REORDER.GetType());
            if (text.CompareTo(REORDER) == 0)
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        protected override void OnItemDrag(ItemDragEventArgs e)
        {
            base.OnItemDrag(e);
            if (!this.AllowRowReorder)
            {
                return;
            }
            base.DoDragDrop(REORDER, DragDropEffects.Move);
        }
        #endregion //EO Reorder Item drag n drop
    }
}
